package com.v5ba.encryptserver.common;

import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Component
@Slf4j
public class EncryptAOP {
    @Pointcut("execution(* com.v5ba.encryptserver.*.controller.*.*(..))")
    public void pointCut(){}

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method targetMethod = signature.getMethod();
        boolean isEncryptHttp = targetMethod.isAnnotationPresent(Encrypt.class);
        ResponseVO responseVO = null;
        if (isEncryptHttp) {
            HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
            String encryptData = request.getParameter("encryptData");
            String encryptKey = request.getParameter("encryptKey");
            try {
                String _data = decrypt(encryptKey, encryptData);
                Object[] args = joinPoint.getArgs();
                if (args != null && args.length > 0) {
                    args[0] = JSONUtil.toBean(_data, args[0].getClass());
                }
                responseVO = (ResponseVO)joinPoint.proceed(args);
            }catch (Exception e){
                responseVO = RespUtil.fail("接口异常："+e.getMessage());
            }
            encrypt(responseVO);
            return responseVO;
        }
        return joinPoint.proceed();
    }
    private String decrypt(String encryptKey, String encryptData) throws Exception {
        // 解密key 获取AES密钥
        byte[] keyByte = null;
        try {
            RSA rsa = SecureUtil.rsa(Constant.PRIVATE_KEY, null);
            keyByte = rsa.decrypt(encryptKey, KeyType.PrivateKey);
        } catch (Exception e) {
            throw new Exception("参数错误，解密key失败");
        }
        // 解密encrypt
        try {
            AES aes = new AES(Mode.ECB, Padding.ISO10126Padding, keyByte);
            return aes.decryptStr(encryptData);
        } catch (Exception e) {
            throw new Exception("参数错误，解密encrypt失败");
        }
    }
    private void encrypt(ResponseVO responseVO){
        if (RespUtil.isSuccess(responseVO) && responseVO.getData() != null){
            byte[] keyByte = GengerCode.getCode(16).getBytes();
            AES aes = new AES(Mode.ECB, Padding.ISO10126Padding, keyByte);
            String encryptData = aes.encryptBase64(JSONUtil.toJsonStr(responseVO));
            // 加密key
            RSA rsa = SecureUtil.rsa(null , Constant.PUBLIC_KEY);
            String encryptKey = rsa.encryptBase64(keyByte, KeyType.PublicKey);
            // 签名
            JSONObject param = JSONUtil.createObj();
            param.put("encryptData", encryptData);
            param.put("encryptKey", encryptKey);
            responseVO.setData(param);
        }

    }
}
